test_building <- readRDS('test_building.Rds')
test_streets <- readRDS('test_streets.Rds')
test_parcels <- readRDS('test_parcels.Rds')
test_area <- readRDS("test_area.Rds")

Plot Test Area Data

tm_shape(test_parcels) + tm_polygons("green", alpha = 0.4) +
  tm_shape(test_building, is.master = TRUE) + tm_polygons(col = "blue") +
  tm_shape(test_streets) + tm_lines(col = "red")

Estimate Setback

Split building polygons into line segments and find centroid of each line

buildings_line_centroids <- st_segments(test_building, progress = FALSE) %>%
  rename(geometry = result) %>% 
  st_centroid()

Identify distance from each building side centroid to nearest street centerline

nn <- st_nn(buildings_line_centroids, test_streets, returnDist = TRUE, progress = FALSE)

buildings_line_centroids$nn_dst <- unlist(nn$dist)

Retain only closest building side centroid

  • Blue dot represents centroid that will be retained
closest_centroid <- buildings_line_centroids %>% 
  group_by(FID) %>% 
  top_n(-1)

tm_shape(test_streets) + tm_lines(col = "red") +
  tm_shape(buildings_line_centroids) + tm_dots("green") +
  tm_shape(closest_centroid) + tm_dots("blue")

Genereate straight line from nearest building side centroid to nearest point on street network

setback_line <- st_connect(closest_centroid, test_streets, progress = FALSE)

setback_line <- st_as_sf(setback_line)

Erase portion of line that does not cover parcel dataset, as method to estimate distance from building edge to edge of right-of-way

setback_line_over_parcel <- st_intersection(setback_line, test_parcels) %>% 
  mutate(length_ft = as.numeric(st_length(.))) %>% 
  select(length_ft)

tm_shape(test_building, is.master = TRUE) + tm_polygons(col = "black") +
  tm_shape(test_streets) + tm_lines(col = "green") +
  tm_shape(setback_line) + tm_lines(col = "blue", lwd = 2) +
  tm_shape(setback_line_over_parcel) + tm_lines(col = "red", lwd = 2)
setback_parcel_only_centroid <- st_centroid(setback_line_over_parcel)

setback_centroid <- setback_line %>% 
  mutate(length_ft = as.numeric(st_length(.))) %>% 
  st_centroid()

summary_grid <- st_make_grid(test_area, cellsize = 1320, square = FALSE, crs = 2236) %>% st_as_sf() %>% 
  mutate(id = row_number()) %>% 
  select(id)

summary_grid_parcel <- st_join(summary_grid, setback_parcel_only_centroid) %>% 
  group_by(id) %>% 
  summarize(median_parcel_setback_ft = mean(length_ft))

summary_grid_centroid <- st_join(summary_grid, setback_centroid) %>% 
  group_by(id) %>% 
  summarize(median_setback_centerline = mean(length_ft))

Summarize reults to grid area

  • Average setback based on two versions: building edge to centerline, and building edge to centerline with public right-of-way removed from estimate
parcel_length <- tm_shape(summary_grid_parcel) + tm_polygons(col = "median_parcel_setback_ft", breaks = c(10, 20, 30, 50, 100, 200))

full_length <- tm_shape(summary_grid_centroid) + tm_polygons(col = "median_setback_centerline", breaks = c(10, 20, 30, 50, 100, 200))

tmap_arrange(parcel_length, full_length, sync = TRUE)